package com.miracle9.game.server.message;

import com.miracle9.game.util.GameParameterAssist;
import com.miracle9.game.util.MyApplicationContext;
import com.miracle9.game.util.MyUtil;
import flex.messaging.io.SerializationContext;
import flex.messaging.io.amf.Amf3Input;
import flex.messaging.io.amf.Amf3Output;
import net.sf.json.JSONObject;
import net.sf.json.groovy.GJson;
import org.apache.log4j.Logger;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.service.IoHandler;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
import org.springframework.stereotype.Service;
import wox.serial.EncodeBase64;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

@Service("bcbmSocketHandler")
public class BcbmSocketHandler implements IoHandler {

    private Logger logger;
    public static Set<IoSession> x = new HashSet();

    public BcbmSocketHandler() {
        this.logger = Logger.getLogger(BcbmSocketHandler.class);
    }

    public void exceptionCaught(IoSession session, Throwable arg1)
            throws Exception {
        session.close(true);
    }

    public void messageReceived(IoSession session, Object message)
            throws Exception {
        try {
            IoBuffer buffer = (IoBuffer) message;
            byte[] contentBytes = new byte[buffer.getInt()];
            buffer.get(contentBytes);
            contentBytes = MyUtil.Base64Decode(contentBytes, GameParameterAssist.bd.get(session));
            Amf3Input ai = new Amf3Input(SerializationContext.getSerializationContext());
            ai.setInputStream(new ByteArrayInputStream(contentBytes));
            Map<String, Object> map = (Map) ai.readObject();

            String url = (String) map.get("method");
            Object[] args = (Object[]) map.get("args");

            if (url.contains("heart")) {
                return;
            }

            String[] urls = url.split("/");
            String beanId = urls[0];
            String method = urls[1];
            Object[] args_login = new Object[args.length + 1];
            for (int i = 0; i < args.length; i++) {
                args_login[i] = args[i];
            }
            args_login[(args_login.length - 1)] = session;
            args = args_login;
            Object service = MyApplicationContext.a().getBean(beanId);
            Method m = service.getClass().getDeclaredMethod(method, getClasses(args));
            Object result = m.invoke(service, args);
            if (result != null) {
                AmfMessageSend.storageMethodOperating.notifyAllOperating(new StorageMethodEntity(session, method, new Object[]{result}));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private Class<?>[] getClasses(Object[] args) {
        try {
            Class[] classArray = new Class[args.length];
            for (int i = 0; i < args.length; i++) {
                classArray[i] = args[i].getClass();
                if ((args[i] instanceof Integer)) {
                    classArray[i] = Integer.TYPE;
                } else if ((args[i] instanceof Boolean)) {
                    classArray[i] = Boolean.TYPE;
                } else if ((args[i] instanceof Map)) {
                    classArray[i] = Map.class;
                } else if ((args[i] instanceof Long)) {
                    classArray[i] = Long.TYPE;
                } else if ((args[i] instanceof Double)) {
                    classArray[i] = Double.TYPE;
                } else if ((args[i] instanceof IoSession)) {
                    classArray[i] = IoSession.class;
                } else if ((args[i] instanceof Float)) {
                    classArray[i] = Float.TYPE;
                }
            }
            return classArray;
        } catch (Exception e) {
            this.logger.error("", e);
        }
        return null;
    }

    public void messageSent(IoSession arg0, Object arg1)
            throws Exception {
    }

    public void sessionClosed(IoSession session)
            throws Exception {
        GameParameterAssist.bd.remove(session);
        x.remove(session);
        GameParameterAssist.bcbmUserId = new ConcurrentHashMap();
        GameParameterAssist.bcbmUserList = new ConcurrentHashMap();
    }

    public void sessionCreated(IoSession arg0)
            throws Exception {
    }

    public void sessionIdle(IoSession session, IdleStatus arg1)
            throws Exception {
        session.close(true);
    }

    public void sessionOpened(IoSession session)
            throws Exception {
        try {
            this.logger.info("sessionOpened...");
            x.add(session);
            Map<String, Object> arg = new HashMap();
            String key = MyUtil.substringLength(16);
            GameParameterAssist.bd.put(session, key);
            String indexStr = key.substring(0, 1);
            String lastStr = key.substring(key.length() - 1, key.length());
            key = key.substring(1, key.length() - 1);
            StringBuilder sb = new StringBuilder(key);
            key = indexStr + sb.reverse() + lastStr;
            byte[] keys = EncodeBase64.encode(key.getBytes());
            key = new String(keys);
            arg.put("key", key);

            HashMap<String, Object> map = new HashMap();
            map.put("method", "manageService/sendServerTime");
            map.put("args", new Object[]{arg});
            ByteArrayOutputStream bout = new ByteArrayOutputStream();
            Amf3Output amf3Output = new Amf3Output(SerializationContext.getSerializationContext());
            amf3Output.setOutputStream(bout);
            amf3Output.writeObject(map);
            amf3Output.flush();
            amf3Output.close();
            byte[] content_out = bout.toByteArray();
            IoBuffer bb = IoBuffer.allocate(content_out.length + 4);
            bb.putInt(content_out.length);
            bb.put(content_out);
            bb.flip();
            session.write(bb);
        } catch (Exception e) {
            this.logger.error("", e);
        }
    }

}
